﻿package {
	import cn.rayYee.loader.SimpleLoad;
	import cn.rayYee.loader.LoadTip;
	import flash.display.Graphics;
	import flash.display.Loader;
	import flash.display.MovieClip;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.events.TimerEvent;
	import flash.events.ProgressEvent;
	import flash.text.TextField;
	import flash.utils.Timer;
	
	import td.*;
	import td.projectiles.*;
	import td.towers.*;
	import td.utils.*;
	import td.data.*;
	import td.Global.*;
	import td.ITd.*;
	import td.control.*;
	import cn.rayYee.utils.CopyRight;

	import com.bit101.components.*;
	import cn.rayYee.display.*;

	[SWF(width="900", height="560", frameRate="30", backgroundColor="#ffffff")]
	/**
	 * 123大战常纺院
	 * 
	 * @author RayYee 
	 * @link http://riavs.cn/
	 * @version alpha
	 */
	public class MagicTD extends Sprite
	{
		private var globalUpdate:updata = updata.getInstance();
		private var currentLevel:int = 1;//当前波数
		private var currentLevObj:Object;//当前关卡数据
		public var clickTower:Tower;//点击的塔
		
		//tools顶部工具栏
		private var uptools:ITool;
		
		//lib
		public var towerlibs:Loader;
		public var creeplibs:Loader;
		public var bulletlibs:Loader;
		
		// Timers
		protected var creep_timer :Timer;
		protected var cleanup_timer :Timer;
		
		// Sprites
		protected var backgroundMC :Sprite = new Sprite();
		protected var bulletMC :Sprite     = new Sprite();
		protected var creepMC :Sprite      = new Sprite();
		protected var towerMC :Sprite      = new Sprite();
		
		// Objects
		protected var bullets :Array = new Array();
		protected var creeps :Array  = new Array();
		protected var towers :Array  = new Array();
		protected var map :Map;
		
		// Other variables
		protected var starting_point :Array;
		protected var ending_point :Array;
		protected var points :Array;
		protected var full_width :int  = 900;
		protected var full_height :int = 560;
		public var grid_size :int;
		
		/**
		 * Constructor method for our application
		 * 
		 * @constructor
		 * @access public
		 * @return void
		 */
		public function MagicTD()
		{
			// for testing
			this.points = [[2, -1], [2, 5], [6, 5], [6, 26], [28, 26], [28, 4], [12, 4], [12, 19], [22, 19], [22, 12], [36, 12]];
			this.grid_size = 20;
			
			libLoader()
			var cr:CopyRight = new CopyRight(this,"version:alpha 1.0");
		}
		
		/**
		 * loader ui - tower creep map & bullet
		 * Could you add me in social city? I can not invited!
		 */
		private function libLoader():void {
			addEventListener(MouseEvent.MOUSE_DOWN, onstageDown);
			function onstageDown(e:MouseEvent):void {
				loader_mc.load_txt.visible=loader_mc.load_txt.visible ?false:true;
			}
			loader_mc.load_txt.visible = false;
			var loadcount:int = 3;
			var sloader:SimpleLoad=new SimpleLoad();
			var cloader:SimpleLoad = new SimpleLoad();
			var bloader:SimpleLoad = new SimpleLoad();
			
			sloader.loading("lib/towers/BasicTower.swf","basictower");
			cloader.loading("lib/creeps/BasicCreep.swf", "basiccreep");
			bloader.loading("lib/bullets/BasicBullet.swf", "basicbullet");
			
			sloader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoadCompleteHandler);
			cloader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoadCompleteHandler);
			bloader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoadCompleteHandler);
			
			sloader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, onLoadProgress);
			cloader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, onLoadProgress);
			bloader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, onLoadProgress);
			function onLoadProgress(e:ProgressEvent):void {
				if (e.target.loader.idObj == "basictower") {
					LoadTip.autoScrollV(loader_mc.load_txt,"\n已加载完炮塔" + Math.floor(e.bytesLoaded / e.bytesTotal * 100) + "%");
				}
				if (e.target.loader.idObj == "basiccreep") {
					LoadTip.autoScrollV(loader_mc.load_txt,"\n已加载完怪物" + Math.floor(e.bytesLoaded / e.bytesTotal * 100) + "%");
				}
				if (e.target.loader.idObj == "basicbullet") {
					LoadTip.autoScrollV(loader_mc.load_txt,"\n已加载完子弹" + Math.floor(e.bytesLoaded / e.bytesTotal * 100) + "%");
				}
			}
			function onLoadCompleteHandler(e:Event):void {
				loadcount--;
				if (e.target.loader.idObj == "basictower") {
					towerlibs = e.target.loader;
					LoadTip.autoScrollV(loader_mc.load_txt,"\n炮塔已加载完毕^^");
				}
				if (e.target.loader.idObj == "basiccreep") {
					creeplibs = e.target.loader;
					LoadTip.autoScrollV(loader_mc.load_txt,"\n怪物已加载完毕^^");
				}
				if (e.target.loader.idObj == "basicbullet") {
					bulletlibs = e.target.loader;
					LoadTip.autoScrollV(loader_mc.load_txt,"\子弹已加载完毕^^");
				}
				if (loadcount == 0) {
					removeEventListener(MouseEvent.MOUSE_DOWN, onstageDown);
					removeChild(loader_mc);
					
					
					// this.setupTarget();
					currentLevObj = LevelControl.tollgate(currentLevel);
					drawBackground();
					setupMap();
					
					var lg:logo = new logo();
					addChild(lg);
					lg.x = 300;
					lg.y = 230;
					
					setupTimers();
					setupListeners();

					
					addChild(creepMC);
					addChild(bulletMC);
					uptools = new toolmc();
					addChild(uptools as MovieClip);
					
					
					creatUser();
					test();
					addChild(towerMC);
				}
				
			}
		}
		
		
		/**
		 * 创建玩家
		 */
		private function creatUser():void {
			new UserData("guest",800,20);//test
			uptools.updataMoney(800);
		}
		
		/**
		 * UI
		 * 
		 */
		protected function test() :void
		{
			var tipPanel:Panel = new Panel(this, 700, 0);
			tipPanel.setSize(200, 600);
			
			var tipWindow:Window = new Window(tipPanel, 0, 400, "Tower Dialog Box");
			tipWindow.setSize(198, 198);
			tipWindow.draggable = false;
			
			var powerlabel:Label = new Label(tipPanel,100,300);
			var powerSlider:HUISlider = new HUISlider(tipPanel, 0, 300, "Grid Size", function (e:Event):void {
				
			});
			powerlabel.text = String(powerSlider.value);
			var tiplabel:Label = new Label(tipWindow, 0, 50,"next level requires "+ 800 +" cions!");
			var towerUp:PushButton = new PushButton(tipWindow, 0,100, "Upgrade Tower", function (e:MouseEvent):void { 
				
			} );
			
			var fps:FPSMeter = new FPSMeter(tipPanel);
			// Set up buttons for towers	
			var aitem:RedButton = new RedButton(tipPanel, 0, 20, "100", testFire, "t8button");
			var bitem:RedButton = new RedButton(tipPanel, 30, 20, "100", testNormal, "t12button");
			var citem:RedButton = new RedButton(tipPanel, 60, 20, "100", testIce, "t9button");
			var ditem:RedButton = new RedButton(tipPanel, 0, 80, "5600", null, "t10button");
			var eitem:RedButton = new RedButton(tipPanel, 30, 80, "6500", null, "t11button");
			var fitem:RedButton = new RedButton(tipPanel, 60, 80, "4500", null, "t2button");
			var hitem:RedButton = new RedButton(tipPanel, 0, 140, "7800", null, "t3button");
			var iitem:RedButton = new RedButton(tipPanel, 30, 140, "10000", null, "t4button");
			var jitem:RedButton = new RedButton(tipPanel, 60, 140, "1200", null, "t5button");
			
			var levelButton:PushButton = new PushButton(tipPanel, 0, 200, ">>>", function(e:MouseEvent):void {
				if (creep_timer.currentCount == 0) {
					creep_timer.start();
				}
			});
		}
		
		protected function testNormal(e :MouseEvent) :void
		{
			var t :Tower = new ArtilleryTower(this, "tower_12");
			t.x = this.parent.mouseX;
			t.y = this.parent.mouseY;
			t.price = 100;
			
			if (GlobalUser.userData.nUMoney < t.price) return;
			
			this.towers.push(t);
			this.towerMC.addChild(t);
			(t.towerMC as MovieClip).turret.stop();
			(t.towerMC as MovieClip).Stars.stop();
			globalUpdate.updateMoney(GlobalUser.userData.nUMoney - t.price);
			uptools.updataMoney(GlobalUser.userData.nUMoney);
		}
		
		protected function testFire(e :MouseEvent) :void
		{
			var t3 :Tower = new Tower(this, "tower_8");
			t3.x = this.parent.mouseX;
			t3.y = this.parent.mouseY;
			t3.price = 100;
			t3.rate = 10;
			t3.power = 30;
			t3.actNum = 5;
			
			if (GlobalUser.userData.nUMoney < t3.price) return;
			
			this.towers.push(t3);
			this.towerMC.addChild(t3);
			(t3.towerMC as MovieClip).turret.stop();
			(t3.towerMC as MovieClip).Stars.stop();
			globalUpdate.updateMoney(GlobalUser.userData.nUMoney - t3.price);
			uptools.updataMoney(GlobalUser.userData.nUMoney);
		}
		
		protected function testIce(e :MouseEvent) :void
		{
			var t2 :Tower = new IceTower(this, "tower_9");
			t2.x = this.parent.mouseX;
			t2.y = this.parent.mouseY;
			t2.price = 200;
			
			if (GlobalUser.userData.nUMoney < t2.price) return;
			
			this.towers.push(t2);
			this.towerMC.addChild(t2);
			(t2.towerMC as MovieClip).Stars.stop();
			globalUpdate.updateMoney(GlobalUser.userData.nUMoney - t2.price);
			uptools.updataMoney(GlobalUser.userData.nUMoney);
		}
		
		/**
		 * Draw the background graphics for this game
		 * 
		 * @return void
		 */
		protected function drawBackground() :void
		{
			var g :Graphics = this.backgroundMC.graphics;
			g.beginFill(0xe4e4e4);
			g.drawRect(0, 0, this.full_width, this.full_height);
			g.endFill();
			
			// Draw vertical hash marks
			g.lineStyle(1, 0xaaaaaa);
			for (var i :int = 0; i < Math.round(this.full_width / this.grid_size); i++)
			{
				g.moveTo(i * this.grid_size, 0);
				g.lineTo(i * this.grid_size, this.full_height);
			}
			
			// Draw horizontal hash marks
			for (i = 0; i < Math.round(this.full_height / this.grid_size); i++)
			{
				g.moveTo(0, i * this.grid_size);
				g.lineTo(this.full_width, i * this.grid_size);
			}
			
			this.addChild(this.backgroundMC);
		}
		
		/**
		 * Set up the map with the points assigned to this member variable
		 * 
		 * @return void
		 */
		protected function setupMap() :void
		{
			this.map = new Map(this.points, this.grid_size, this);
			this.map.drawRoad();
			this.addChild(this.map);
		}
		
		/**
		 * Set up any timers we need and start them
		 * 
		 * @access protected
		 * @return void
		 */
		protected function setupTimers() :void
		{
			this.creep_timer = new Timer(1000,currentLevObj.cn);
			this.creep_timer.start();
			
			this.cleanup_timer = new Timer(15000);
			this.cleanup_timer.start();
		}
		
		/**
		 * Set up any listeners we need for this application
		 * 
		 * @access protected
		 * @return void
		 */
		protected function setupListeners() :void
		{
			this.creep_timer.addEventListener(TimerEvent.TIMER, createCreep);
			this.creep_timer.addEventListener(TimerEvent.TIMER_COMPLETE, updataLevel);
			this.cleanup_timer.addEventListener(TimerEvent.TIMER, cleanup);
			this.addEventListener(MouseEvent.CLICK, handleGlobalClick, true);
		}
		
		/**
		 * 更新关卡
		 */
		private function updataLevel(e:TimerEvent):void {
			currentLevel++;
			if (currentLevel > 3) return;//当前只有3波
			currentLevObj = LevelControl.tollgate(currentLevel);
			creep_timer.repeatCount = currentLevObj.cn;
			creep_timer.reset();
		}
		
		
		/**
		 * Creates a new creep with every timer tic
		 * 
		 * @access protected
		 * @param {TimerEvent} e The creep timer
		 * @return void
		 */
		protected function createCreep(e :TimerEvent) :void
		{
			var c :Creep = new Creep(currentLevObj.cd,this.points, this);
			//var nHP:Number = 2000;
			//var nDEF:Number = 100;
			//c.setHP(nHP);//设置hp
			//c.setDEF(nDEF);//设置防御
			//if (Math.random() < 0.02) {//随机变异,2%几率
				//c.scaleX = c.scaleY = 1.5;
				//c.setHP(nHP*10);
				//c.setDEF(nDEF * 10);
				//c.reward = 1000;
			//}
			//怪死亡后得到奖励，更新金币
			c.addEventListener(Const.CreepDestroyed, function(e:Event):void {
				globalUpdate.updateMoney(GlobalUser.userData.nUMoney + c.reward);
				uptools.updataMoney(GlobalUser.userData.nUMoney);
			});
			c.addEventListener(Const.CreepWin, function (e:Event):void {
				
			});
			this.creeps.push(c);
			this.creepMC.addChild(c);
		}
		
		/**
		 * Handles the user's clicking on anything not handled within an object
		 * 
		 * @access protected
		 * @param {MouseEvent} e the click event
		 * @return void
		 */
		protected function handleGlobalClick(e :MouseEvent) :void
		{
			clearSelections();
		}
		
		/**
		 * Fires a bullet from the provided tower towards the next creep in range
		 * 
		 * @access public
		 * @param {Tower} the tower from which to fire
		 * @return void
		 */
		public function fire(t :Tower) :void
		{
			try {//优化时 需去掉try
				var arr_c :Array  = this.obtainTarget(t.x, t.y, t.getRange(),t.actNum);
				var c :Creep  = arr_c[0];
				for (var i:int = 0; i < arr_c.length; i++ ) {
					var b :Bullet = t.getNewBullet(arr_c[i]);
					this.bullets.push(b);
					this.bulletMC.addChild(b);
				}
				
				
				//随着creep调整tower方向  set turret
				var diffX :int = Math.abs(t.x - c.x);
				var diffY :int = Math.abs(t.y - c.y);
				var dist :int = Math.round(Math.sqrt((diffX * diffX) + (diffY * diffY)));
				var sin_A:Number = diffY / dist;
				var asin_A:Number = Math.asin(sin_A);
				var cFrame:Number;
				if (c.x < t.x) {
					if (c.y < t.y) {
						cFrame = asin_A * 180 / Math.PI / 5;
					}else if (c.y > t.y) {
						cFrame = (360 - asin_A * 180 / Math.PI ) / 5;
					}else if (c.y == t.y) {
						cFrame = 1;
					}
				}else if (c.x > t.x) {
					if (c.y < t.y) {
						cFrame = (180 - asin_A * 180 / Math.PI) / 5;
					}else if (c.y > t.y) {
						cFrame = (180 + asin_A * 180 / Math.PI) / 5;
					}else if (c.y == t.y) {
						cFrame = 180 / 5;
					}
				}else if (c.x == t.x) {
					if (c.y < t.y) {
						cFrame = 90 / 5;
					}else if (c.y > t.y) {
						cFrame = 270 / 5;
					}
				}
				(t.towerMC as MovieClip).turret.gotoAndStop(Math.ceil(cFrame));
			}
			catch (e :Error)
			{
				// Do nothing, since we have no targets in range
			}
		}
		
		/**
		 * Time for resource cleanup
		 * 
		 * @access protected
		 * @param {TimerEvent} e The timer event calling this method
		 * @return void
		 */
		protected function cleanup(e :TimerEvent) :void
		{
			var i :int = 0;
			
			// First, let's clean up the dead bullets
			for (i = 0; i < this.bullets.length; i++)
			{
				var b :Bullet = this.bullets[i];
				if (b.isDestroyed())
				{
					this.bulletMC.removeChild(b);
					this.bullets.splice(i, 1);
				}
			}
			
			// Now, let's clean up dead creeps
			for (i = 0; i < this.creeps.length; i++)
			{
				var c :Creep = this.creeps[i];
				if (c.isDestroyed())
				{
					this.creepMC.removeChild(c);
					this.creeps.splice(i, 1);
				}
			}
		}
		
		/**
		 * Finds and returns the first creep that is within the given radius from the position provided
		 * 
		 * @access public
		 * @param {int} posX the X coordinate
		 * @param {int} posY the Y coordinate
		 * @param {int} radius the range to scan
		 * @return Creep
		 */
		public function obtainTarget(posX :int, posY :int, radius :int,actnum:int) :Array
		{
			var  arr:Array = [];
			targetLoop: for (var i :int = 0; i < this.creeps.length; i++)
			{
				
				// Calculate distance to creep
				var diffX :int = Math.abs(posX - this.creeps[i].x);
				var diffY :int = Math.abs(posY - this.creeps[i].y);
				var dist :int = Math.round(Math.sqrt((diffX * diffX) + (diffY * diffY)));
				
				if (dist <= radius && !this.creeps[i].isDestroyed())
				{
					actnum--;
					arr.push(this.creeps[i]);
					if (actnum <= 0) return arr;
					// return this creep
					//return this.creeps[i];
				}
			}
			return arr;
			//throw new Error('No targets available');
		}
		
		/**
		 * Since this is the global click handler, we want to deselect anything that was previously selected
		 * 
		 * @access public
		 * @return void
		 */
		public function clearSelections() :void
		{
			// Deselect towers
			for (var i :int = 0; i < this.towers.length; i++)
			{
				towers[i].deselect();
			}
			
			// Deselect creeps
			for (i = 0; i < this.creeps.length; i++)
			{
				//creeps[i].deselect();
			}
		}
		
		/**
		 * Calculates the pixels to the given point on the grid
		 * 
		 * @access public
		 * @param {Number} x the point to calculate
		 * @param {Boolean} b whether or not to center the point
		 * @return Number
		 */
		public function getPointToPixels(x :Number, b :Boolean) :Number
		{
			var r :int = x * this.grid_size;
			if (b == true)
			{
				return r - (this.grid_size / 2);
			}
			
			return r;
		}
	}
}
